
#include <iostream>
#include <string>
#include <functional>
#include "Concepts.h"

template<class T>
struct HasPlus : Concepts::Concept
{
	struct Concept {};
	~HasPlus()
	{
		T a{}, b{}, value;
		value = a + b;
	}
};

DefineConcept(Extends, 
	ConceptParams(class T, class U), 
	ConceptRequires(
{
	[]() {
		T* t=nullptr; U* u=nullptr;
		u = t;
	}();
}))

struct ClassX {

};

struct ClassY : ClassX
{
	ClassY operator+(const ClassY& other) const {
		return *this;
	}
};

// Refinement
template<class T, class U>
struct ExtendHasPlus : Extends<T, U>, HasPlus<T>
{
	struct Concept {};
	virtual ~ExtendHasPlus()
	{
	}
};

template<class T>
struct INeedAnOperatorPlus : require(HasPlus<T>) {};

template<class Parent, class Child>
struct INeedTwoRelatedClass : require(Extends<Child, Parent>) {};

// Modeling
template<class Parent, class Child>
struct INeedTwoRelatedClassWithOperatorPlus : require(Extends<Child, Parent>), require(HasPlus<Child>) {};

template<class Parent, class Child>
struct INeedTwoRelatedClassWithOperatorPlusToo : require(ExtendHasPlus<Child, Parent>) {};

template<class T, class = require(HasPlus<T>)>
auto id(const T& x) {
	return x;
}

int main()
{
	INeedAnOperatorPlus<int>();
	INeedAnOperatorPlus<std::string>();
//	INeedAnOperatorPlus<ClassX>();
	INeedTwoRelatedClass<HasPlus<int>::Concept, INeedAnOperatorPlus<int>>();
	INeedTwoRelatedClass<Concepts::Concept, HasPlus<int>>();
//	INeedTwoRelatedClass<int, bool>();
	INeedTwoRelatedClassWithOperatorPlus<ClassX, ClassY>();
//	INeedTwoRelatedClassWithOperatorPlus<Concepts::Concept, HasPlus<int>>();
	INeedTwoRelatedClassWithOperatorPlusToo<ClassX, ClassY>();
//	INeedTwoRelatedClassWithOperatorPlusToo<Concepts::Concept, HasPlus<int>>();
}

